package com.kinsin.kinsinlogsystem;

import android.app.Dialog;
import android.content.Context;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;

import androidx.constraintlayout.widget.Group;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

// region 使用示例代码
//new UploadLogDialog(context,
//        new UploadLogDialog.UploadLogParams.Builder()
//        .setTitle("测试标题")
//        .setBaseLogPath("/storage/emulated/legacy/example/logRollDir/")
//        .setZipPath("/storage/emulated/legacy/example/logZipPath/")
//        .setRecipientEmail("123456789@qq.com")
//        .addCc("321654987@qq.com")
//        .addCc("125896347@qq.com")
//        .setZipPartSize(40 * 1024 * 1024) // 40MB
//        .build()).show();
// endregion 使用示例代码

/**
 * 上传日志对话框
 * 使用示例：(最上方留有方便复制的代码)
 * new UploadLogDialog(context,
 * new UploadLogDialog.UploadLogParams.Builder()
 * .setTitle("测试标题")
 * .setBaseLogPath("/storage/emulated/legacy/example/logRollDir/") // 设置基础日志路径
 * .setZipPath("/storage/emulated/legacy/example/logZipPath/") // 设置压缩路径
 * .setRecipientEmail("123456789@qq.com") // 设置收件人邮箱
 * .addCc("321654987@qq.com") // 添加抄送人邮箱1
 * .addCc("125896347@qq.com") // 添加抄送人邮箱2 ，可以添加多个，也可以用列表添加
 * .setZipPartSize(40 * 1024 * 1024) // 40MB
 * .build())
 * .show();
 */
public class UploadLogDialog extends Dialog {
    private static final String TAG = "UploadLogDialog";

//    private Group progressGroup;
    private Group progressValueGroup;
    private ProgressBar mProgressBar;
    private ProgressBar mLoadingBar;
    private TextView mProgressText;
    private TextView mContentText;
    private ScrollView mScrollView;
    private Button mCancelButton;
    private Button mConfirmButton;
    private final ZipManager zipManager = new ZipManager();
    private final StringBuilder operateLog = new StringBuilder(); // 压缩操作日志
    private final StringBuilder logEmailOutputInfo = new StringBuilder(); // 日志发送邮件输出信息

    // 新增参数类实例
    private final UploadLogParams mParams;

    // 新构造方法
    public UploadLogDialog(Context context, UploadLogParams params) {
        super(context);
        this.mParams = params;
    }

    // 参数校验方法
    private boolean validateParams(String tag) {
        Log.w(TAG, "validateParams: " + tag);
        Log.w(TAG, "validateParams: " + mParams);
        if (mParams == null) {
//            throw new IllegalArgumentException("UploadLogParams cannot be null");
            Log.w(TAG, "validateParams: UploadLogParams cannot be null --- " + tag);
            return false;
        }
        if (mParams.recipientEmail == null || mParams.recipientEmail.isEmpty()) {
//            throw new IllegalArgumentException("Recipient email cannot be empty");
            Log.w(TAG, "validateParams: Recipient email cannot be empty --- " + tag);

            return false;
        }
        return true;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dialog_upload_logcat_layout);

        // 点击外部不可取消
        setCancelable(false);
        setCanceledOnTouchOutside(false);
        Window dialogWindow = getWindow();

        // 背景透明
        if (dialogWindow != null) {
            dialogWindow.setBackgroundDrawableResource(android.R.color.transparent);
            dialogWindow.setGravity(Gravity.CENTER);
            WindowManager.LayoutParams lp = dialogWindow.getAttributes();
            lp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
            lp.gravity = Gravity.CENTER;
            dialogWindow.setAttributes(lp);
        } else {
            Log.e(TAG, "dialogWindow is null");
        }

        initView();
        initData();
        initAction();
    }

    private void initView() {
        // 初始化控件
//        progressGroup = findViewById(R.id.progressBarGroup);
        progressValueGroup = findViewById(R.id.progressBarValueGroup);
        mContentText = findViewById(R.id.contentUploadLog);
        mProgressBar = findViewById(R.id.progressUploadLog);
        mLoadingBar = findViewById(R.id.loadingBar);
        mProgressText = findViewById(R.id.progressShowText);
        mCancelButton = findViewById(R.id.cancelBtnUploadLog);
        mConfirmButton = findViewById(R.id.confirmBtnUploadLog);
        mScrollView = findViewById(R.id.scrollContent);
    }

    private void initData() {
        // 初始化数据
        mContentText.setText("是否开启日志文件上传❓");
        mProgressBar.setProgress(0);
        mProgressText.setText("0/100");

        // 初始隐藏所有进度条组件
//        progressGroup.setVisibility(View.GONE);
        progressValueGroup.setVisibility(View.GONE);
    }

    private void initAction() {
        // 取消按钮点击事件
        mCancelButton.setOnClickListener(new FilterClickListener() {
            @Override
            protected void onFilterClick(View view) {
                dismiss();
            }
        });

        // 启动一键上传按钮点击事件
        mConfirmButton.setOnClickListener(new FilterClickListener() {
            @Override
            protected void onFilterClick(View view) {
                // 显示进度条组件
//                progressGroup.setVisibility(View.VISIBLE);
                progressValueGroup.setVisibility(View.VISIBLE);
                mConfirmButton.setVisibility(View.GONE);
                // 开始上传日志
                startUpload();
            }
        });

    }

    /**
     * 开始上传日志
     */
    private void startUpload() {
        if (!validateParams("startUpload")) {
            return;
        }
        // 清空StringBuilder
        operateLog.delete(0, operateLog.length());
        logEmailOutputInfo.delete(0, logEmailOutputInfo.length());
        logEmailOutputInfo.append("主机一键发送日志操作记录").append("\n");
        // 删除已存在的压缩文件
        FileUtils.delete(mParams.zipPath); // 使用参数中的压缩路径
        // 创建压缩包存储路径
        FileUtils.createDir(mParams.zipPath);
        // region 日志收集
        List<File> files = getAllLogFiles(mParams.baseLogPath);
        Log.d(TAG, "startUpload 日志收集 files = " + files.size());
        if (files.isEmpty()) {
            operateLog.append("\n").append("日志文件为空，已停止发送程序");
            updateOperateLog();
        }
        // endregion 日志收集

        // 压缩
        startCompression(files);

    }

    /**
     * 开始压缩
     *
     * @param files
     */
    private void startCompression(final List<File> files) {
        Log.d(TAG, "startCompression");
        if (!validateParams("startCompression")) {
            return;
        }
        operateLog.append("\n").append("正在压缩日志文件...");
        updateOperateLog();
        zipManager.startCompression(files, mParams.zipPath + "/logZipper", mParams.zipPartSize, new ZipManager.ZipProgressListener() {
            @Override
            public void onProgress(int percent) {
                Log.d(TAG, "压缩文件当前进度： " + percent + "/100");
                updateProgress(percent);
            }

            @Override
            public void onComplete(final List<File> zipFiles) {
                // 压缩完成，开始验证
                startValidate(zipFiles, files);
            }

            @Override
            public void onError(Throwable throwable) {
                Log.d(TAG, "错误: " + throwable.getMessage());
                operateLog.append("\n").append("压缩发生错误，已终止").append("\n").append(throwable.getMessage());
                updateOperateLog();
            }

            @Override
            public void onCancel() {
                Log.d(TAG, "压缩已关闭");
                operateLog.append("\n").append("压缩已关闭");
                updateOperateLog();
            }
        });
    }

    /**
     * 验证压缩文件
     *
     * @param zipFiles
     * @param files
     */
    private void startValidate(final List<File> zipFiles, List<File> files) {
        Log.d(TAG, "压缩完成，共有压缩分卷" + zipFiles.size() + "个");
        operateLog.append("\n").append("压缩完成✅ 共有压缩分卷").append(zipFiles.size()).append("个");
        logEmailOutputInfo.append("\n").append("共有压缩分卷").append(zipFiles.size()).append("个");
        updateOperateLog();
        updateProgress(0);
        operateLog.append("\n").append("正在校验压缩文件...");
        updateOperateLog();
        ZipManager.validateZipParts(zipFiles, files, new ZipManager.ValidationCallback() {
            @Override
            public void onValidationProgress(int percent) {
                Log.d(TAG, "验证压缩分卷当前进度： " + percent + "/100");
                updateProgress(percent);
            }

            @Override
            public void onValidationComplete(List<String> errors) {
                // 验证完成,获取错误信息
                String errorInfo = getErrorInfo(errors);
                logEmailOutputInfo.append("\n").append("错误记录：").append(errorInfo);
                // 发送日志
                for (int i = 0; i < zipFiles.size(); i++) {
                    // 是否多分卷
                    boolean isMultiPart = zipFiles.size() > 1;
                    // 是否最后一个分卷
                    boolean isLast = i == zipFiles.size() - 1;
                    sendEmail(zipFiles.get(i), isMultiPart, i, isLast, zipFiles.size());
                }
            }
        });
    }

    /**
     * 发送邮件
     *
     * @param file         文件
     * @param isMultiPart  是否多分卷
     * @param currentIndex 当前分卷索引
     * @param isLast       是否是最后一个分卷
     * @param totalSize    总分卷数
     */
    private void sendEmail(File file, boolean isMultiPart, int currentIndex, boolean isLast, int totalSize) {
        // 将file打包成List<File>，调用sendEmail(List<File> zipFiles)发送
        List<File> files = new ArrayList<>();
        files.add(file);
        sendEmail(files, isMultiPart, currentIndex, isLast, totalSize);
    }

    /**
     * 发送邮件
     *
     * @param zipFiles     文件列表
     * @param isMultiPart  是否多分卷
     * @param currentIndex 当前分卷索引
     * @param isLast       是否是最后一个分卷
     * @param totalSize    总分卷数
     */
    private void sendEmail(List<File> zipFiles, boolean isMultiPart, int currentIndex, boolean isLast, int totalSize) {
        if (!validateParams("sendEmail")) {
            return;
        }
        // 使用参数中的收件人地址和标题模板
        String title = mParams.title + "| 当前：" + (currentIndex + 1) + "/" + totalSize;
        // 隐藏有值的进度条，显示无值的进度条
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                progressValueGroup.setVisibility(View.GONE);
                mLoadingBar.setVisibility(View.VISIBLE);
            }
        });
        // 更新操作日志
        if (isMultiPart && !isLast) {
            // 显示正在上传第几个日志
            operateLog.append("\n").append("正在上传第").append(currentIndex + 1).append("个分卷，请稍后...");
        } else if (isMultiPart) {
            // 显示正在上传最后一个日志
            operateLog.append("\n").append("正在上传最后一个分卷，请稍后...");
        } else {
            operateLog.append("\n").append("正在上传日志，请稍后...");
        }

        updateOperateLog();
        // 无论是否有失败都发送，将失败文件写入到邮件内容中
        EmailSender.getInstance().sendEmailAsync(
                mParams.recipientEmail,
                mParams.ccList,  // 新增抄送参数
                title,
                logEmailOutputInfo.toString(),
                zipFiles,
                new EmailSender.EmailCallback() {
                    @Override
                    public void onSuccess() {
                        Log.d(TAG, "发送邮件成功");
                        if (isMultiPart && !isLast) {
                            // 显示第几个分卷上传成功
                            operateLog.append("\n").append("第").append(currentIndex + 1).append("个分卷上传成功✅");
                        } else if (isMultiPart) {
                            operateLog.append("\n").append("最后一个分卷上传成功✅");
//                            // 删除压缩文件
                            FileUtils.delete(mParams.zipPath);
                            progressValueGroup.setVisibility(View.GONE);
                            mLoadingBar.setVisibility(View.GONE);
                        } else {
                            operateLog.append("\n").append("发送邮件成功✅");
                            // 删除压缩文件
                            FileUtils.delete(mParams.zipPath);
                            progressValueGroup.setVisibility(View.GONE);
                            mLoadingBar.setVisibility(View.GONE);
                        }
                        updateOperateLog();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mCancelButton.setText("完成");
                            }
                        });
                    }

                    @Override
                    public void onFailure(String error) {
                        Log.d(TAG, "发送邮件失败");
                        if (isMultiPart && !isLast) {
                            operateLog.append("\n").append("第").append(currentIndex + 1).append("个分卷上传失败❎");
                        } else if (isMultiPart) {
//                            // 删除压缩文件
//                            FileUtils.delete(mParams.zipPath);
                        } else {
                            operateLog.append("\n").append("发送邮件失败❎");
                            // 删除压缩文件
                            FileUtils.delete(mParams.zipPath);
                        }
                        updateOperateLog();
//                        progressGroup.setVisibility(View.GONE);
                        progressValueGroup.setVisibility(View.GONE);
                        mLoadingBar.setVisibility(View.GONE);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mCancelButton.setText("关闭");
                            }
                        });
                    }
                });
    }

    /**
     * 获取错误信息
     *
     * @param errors
     * @return
     */
    private String getErrorInfo(List<String> errors) {
        StringBuilder errorZipContent = new StringBuilder();
        boolean specialSuccess = isSpecialSuccess(errors);
        if (errors.isEmpty() || specialSuccess) {
            Log.d(TAG, "验证压缩包成功");
            operateLog.append("\n").append("验证压缩包成功 ✅");
            updateOperateLog();
        } else {
            Log.d(TAG, "验证压缩包失败❎ (部分验证失败不影响发送)");
            operateLog.append("\n").append("验证压缩包失败❎ (部分验证失败不影响发送)");
            updateOperateLog();
        }
        // 输出所有的验证错误信息
        for (String error : errors) {
            Log.d(TAG, error);
            errorZipContent.append(error).append("\n");
        }
        return errorZipContent.toString();
    }

    /**
     * 判断特殊成功
     * 由于Log.log和tmpFile日志是持续记录的，所以可能存在CRC校验不通过问题，这个可以忽略
     *
     * @param errors
     * @return
     */
    public boolean isSpecialSuccess(List<String> errors) {
        // 处理集合为 null 的情况
        if (errors == null) {
            return false;
        }

        int errorCount = errors.size();

        // 错误数量必须为 1 或 2
        if (errorCount != 1 && errorCount != 2) {
            return false;
        }

        // 遍历所有错误，检查文件名前缀
        for (String error : errors) {
            // 处理 null 或不符合前缀规则的情况
            if (error == null ||
                    (!error.contains("tmpFile_") && !error.contains("Log.log"))) {
                return false;
            }
        }

        // 全部条件满足时返回 true
        return true;
    }

    private List<File> getAllLogFiles(String baseLogPath) {
        LogFileCollector logFileCollector = new LogFileCollector();
        final List<File> files = logFileCollector.collectSortedLogFiles(baseLogPath);
        Log.d(TAG, "一共收集到日志文件：" + files.size() + "个，准备开始压缩分卷");
        operateLog.append("一共收集到日志文件：").append(files.size()).append("个");
        logEmailOutputInfo.append("一共收集到日志文件：").append(files.size()).append("个");
        updateOperateLog();
        return files;
    }

    /**
     * 更新进度条和显示文本
     *
     * @param progress 当前进度（0-100）
     */
    private void updateProgress(final int progress) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mProgressBar.setProgress(progress);
                mProgressText.setText(String.format("%d/100", progress));
            }
        });
    }

    /**
     * 设置内容文本
     *
     * @param text 内容说明文字
     */
    private void setContentText(final String text) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mContentText.setText(text);
                // 将scrollView移动到最新的位置
                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
            }
        });
    }

    /**
     * 更新操作日志
     */
    private void updateOperateLog() {
        setContentText(operateLog.toString());
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop: 日志上传窗口已关闭");
        zipManager.cancel();
    }

    private static void runOnUiThread(Runnable runnable) {
        Handler mainHandler = new Handler(Looper.getMainLooper());
        mainHandler.post(runnable);
    }


    // 新增参数类
    public static class UploadLogParams {
        private final String recipientEmail; // 目标邮箱
        private final List<String> ccList;  // 抄送列表
        private final String title; // 邮件标题
        private final String baseLogPath; // 日志文件基础路径
        private final String zipPath; // 压缩包路径
        private final long zipPartSize; // 压缩包分卷大小

        private UploadLogParams(Builder builder) {
            this.recipientEmail = builder.recipientEmail;
            this.ccList = builder.ccList;    // 初始化抄送列表
            this.title = builder.title;
            this.baseLogPath = builder.baseLogPath;
            this.zipPath = builder.zipPath;
            this.zipPartSize = builder.zipPartSize;
        }

        public static class Builder {
            private String recipientEmail = ""; // 目标邮箱
            private List<String> ccList = new ArrayList<>(); // 抄送列表
            private String title = ""; // 邮件标题
            private String baseLogPath = ""; // 日志文件基础路径
            private String zipPath = ""; // 压缩包路径
            private long zipPartSize = 5_000_000; // 压缩包分卷大小

            // 设置抄送列表
            public Builder setCcList(List<String> ccList) {
                if (ccList != null) {
                    this.ccList = ccList;
                }
                return this;
            }

            // 添加单个抄送人
            public Builder addCc(String ccEmail) {
                if (ccEmail != null && !ccEmail.isEmpty()) {
                    this.ccList.add(ccEmail);
                }
                return this;
            }

            public Builder setRecipientEmail(String email) {
                this.recipientEmail = email;
                return this;
            }

            public Builder setTitle(String template) {
                this.title = template;
                return this;
            }

            public Builder setBaseLogPath(String path) {
                this.baseLogPath = path;
                return this;
            }

            public Builder setZipPath(String path) {
                this.zipPath = path;
                return this;
            }

            public Builder setZipPartSize(long size) {
                this.zipPartSize = size;
                return this;
            }

            public UploadLogParams build() {
                return new UploadLogParams(this);
            }
        }
    }

}
